//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace Microsoft.Research.ScientificWorkflow.SecurityControls
{
    using System;
    using System.Collections.Generic;
    using Microsoft.Research.DataLayer;
    using ManagementStudioServices.Interfaces;
    using System.Collections.ObjectModel;
    using System.Windows;
    using System.ComponentModel;
    using System.Windows.Input;
    using Microsoft.Research.ScientificWorkflow.UIDesigner.WpfComposite;
    using System.Text.RegularExpressions;
    using Microsoft.Research.ScientificWorkflow.TridentUtilities;

    /// <summary>
    /// 
    /// </summary>
    public class GlobalSettingsPresenter : INotifyPropertyChanged
    {
        #region Private Variables

        /// <summary>
        /// GlobalSettings Window.
        /// </summary>
        private GlobalSettingsView globalSettingsView = null;

        /// <summary>
        /// 
        /// </summary>
        private DataproductGlobalSetting dataProductSetting = null;

        /// <summary>
        /// 
        /// </summary>
        private GlobalSetting setting = null;

        /// <summary>
        /// 
        /// </summary>
        private IRegistryManagerService registryManagerService;

        /// <summary>
        /// 
        /// </summary>
        private string maxValue;

        /// <summary>
        /// 
        /// </summary>
        private string minValue;

        /// <summary>
        /// 
        /// </summary>
        private bool isSourceSelected = false;

        /// <summary>
        /// 
        /// </summary>
        private DataproductGlobalSetting selectedSource;

        #endregion

        #region Public Properties
        /// <summary>
        /// UI List.
        /// </summary>
        public ObservableCollection<DataproductGlobalSetting> dataSourceList { get; set; }

        /// <summary>
        /// Gets or sets the save settings command.
        /// </summary>
        /// <value>The save policy command.</value>
        public ICommand SaveSettingsCommand { get; private set; }

        /// <summary>
        /// Gets or sets the close schedule window command.
        /// </summary>
        /// <value>Close Global Settings window command.</value>
        public ICommand CloseGlobalSettingWindowCommand { get; set; }

        /// <summary>
        /// Gets or sets the max value.
        /// </summary>
        /// <value>The max value.</value>
        public string MaxValue
        {
            get
            {
                return maxValue;
            }
            set
            {
                maxValue = string.IsNullOrEmpty(value) ? "0" : value;
                this.OnNotifyPropertyChanged("MaxValue");
            }
        }

        /// <summary>
        /// Gets or sets the min value.
        /// </summary>
        /// <value>The min value.</value>
        public string MinValue
        {
            get
            {
                return minValue;
            }
            set
            {
                minValue = string.IsNullOrEmpty(value) ? "0" : value;
                this.OnNotifyPropertyChanged("MinValue");
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether this instance is source selected.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance is source selected; otherwise, <c>false</c>.
        /// </value>
        public bool IsSourceSelected
        {
            get { return isSourceSelected; }
            set
            {
                isSourceSelected = value;
                this.OnNotifyPropertyChanged("IsSourceSelected");
            }
        }

        /// <summary>
        /// Gets or sets the selected source.
        /// </summary>
        /// <value>The selected source.</value>
        public DataproductGlobalSetting SelectedSource
        {
            get
            {
                return selectedSource;
            }
            set
            {
                selectedSource = value;

                IsSourceSelected = (null != selectedSource && !selectedSource.DatastoreID.Equals(Guid.Empty)) ? true : false;

                this.MaxValue = value.MaximumSize.ToString();
                this.MinValue = value.MinimumSize.ToString();
                this.OnNotifyPropertyChanged("SelectedSource");
            }
        }

        #endregion

        #region Constructor
        /// <summary>
        /// Initializes a new instance of the <see cref="GlobalSettingsPresenter"/> class.
        /// </summary>
        /// <param name="registryManagerService">The registry manager service.</param>
        public GlobalSettingsPresenter(IRegistryManagerService registryManagerService)
        {
            try
            {
                // initiallize 
                Initialize(registryManagerService);

                // Set the data context to UI.
                globalSettingsView = new GlobalSettingsView();
                globalSettingsView.DataContext = this;

                this.SaveSettingsCommand = new DelegateCommand<object>(p => this.SaveSettings());
                this.CloseGlobalSettingWindowCommand = new DelegateCommand<object>(p => this.CloseGlobalSettingsUI());


                // Open the GlobalSettings UI.
                globalSettingsView.Owner = Application.Current.MainWindow;
                globalSettingsView.ShowDialog();
            }
            catch (TridentCustomException ex)
            {
                TridentErrorHandler.HandleTridentCustomExceptionInUI(ex);
            }
            catch (Exception ex)
            {
                TridentErrorHandler.HandleKnownExceptionsInUI(ex);
            }
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Closes the global settings UI.
        /// </summary>
        private void CloseGlobalSettingsUI()
        {
            globalSettingsView.Close();
        }

        /// <summary>
        /// Saves the settings.
        /// </summary>
        private void SaveSettings()
        {
            try
            {
                if (ValidateInputs())
                {
                    if (!string.IsNullOrEmpty(this.MaxValue))
                        this.SelectedSource.MaximumSize = Int32.Parse(this.MaxValue);

                    if (!string.IsNullOrEmpty(this.MinValue))
                        this.SelectedSource.MinimumSize = Int32.Parse(this.MinValue);

                    string dataProduct = DataProductGlobalSettingService.SaveSettings(this.SelectedSource);
                    registryManagerService.SaveGlobalSettings(dataProduct);

                    globalSettingsView.Close();
                }
            }
            catch (TridentCustomException ex)
            {
                TridentErrorHandler.HandleTridentCustomExceptionInUI(ex);
            }
            catch (Exception ex)
            {
                TridentErrorHandler.HandleKnownExceptionsInUI(ex);
            }
        }

        /// <summary>
        /// Initializes the specified registry manager service.
        /// </summary>
        /// <param name="registryManagerService">The registry manager service.</param>
        private void Initialize(IRegistryManagerService registryManagerService)
        {
            this.registryManagerService = registryManagerService;
            dataSourceList = new ObservableCollection<DataproductGlobalSetting>();

            GetDataReferenceStores(registryManagerService);
        }

        /// <summary>
        /// Gets the data reference stores.
        /// </summary>
        /// <param name="registryManagerService">The registry manager service.</param>
        private void GetDataReferenceStores(IRegistryManagerService registryManagerService)
        {
            // Get all the data reference stores.
            Collection<DataReferenceStore> stores = registryManagerService.GetDataReferenceStores();

            // Get global settings.
            setting = registryManagerService.GetGlobalSetting();

            // Deserialize the setting.
            if (null != setting)
                this.dataProductSetting = DataProductGlobalSettingService.GetSettings(setting.Dataproduct);

            this.InitializeDefaultValues();

            // Initialize dataSourceList.
            if (null != stores)
            {
                foreach (DataReferenceStore store in stores)
                {
                    DataproductGlobalSetting globalSetting = new DataproductGlobalSetting();

                    if (null != this.dataProductSetting &&
                        (store as IObject).ID.ToString().Equals(
                            this.dataProductSetting.DatastoreID.ToString(),
                            StringComparison.CurrentCultureIgnoreCase))
                    {
                        globalSetting.DatastoreID = this.dataProductSetting.DatastoreID;
                        globalSetting.DisplayName = store.Name + " ( " + store.Provider.Name + " )";
                        globalSetting.MaximumSize = this.dataProductSetting.MaximumSize;
                        globalSetting.MinimumSize = this.dataProductSetting.MinimumSize;

                        this.SelectedSource = globalSetting;
                    }
                    else
                    {
                        globalSetting.DatastoreID = (store as IObject).ID;
                        globalSetting.DisplayName = store.Name + " ( " + store.Provider.Name + " )";

                        if (null != this.dataProductSetting)
                        {
                            globalSetting.MaximumSize = this.dataProductSetting.MaximumSize;
                            globalSetting.MinimumSize = this.dataProductSetting.MinimumSize;
                        }
                    }

                    dataSourceList.Add(globalSetting);
                }
            }
        }

        /// <summary>
        /// Initializes the default values.
        /// </summary>
        private void InitializeDefaultValues()
        {
            DataproductGlobalSetting selectSetting = new DataproductGlobalSetting { DatastoreID = Guid.Empty, DisplayName = "Select" };
            if (this.dataProductSetting != null)
            {
                selectSetting.MaximumSize = this.dataProductSetting.MaximumSize;
                selectSetting.MinimumSize = this.dataProductSetting.MinimumSize;
            }

            dataSourceList.Add(selectSetting);
            this.SelectedSource = selectSetting;
        }

        /// <summary>
        /// Validates the inputs.
        /// </summary>
        /// <returns></returns>
        private bool ValidateInputs()
        {
            bool result = true;
            Regex checkSpecialChar = new Regex(@"[\D]");
            string validationError = string.Empty;

            int maximumSize = 0;
            int minimumSize = 0;
            bool isMaxSizeValid = false;
            bool isMinSizeValid = false;

            // Try to parse and validate the inputs.
            isMinSizeValid = Int32.TryParse(this.MinValue, out minimumSize);
            isMaxSizeValid = Int32.TryParse(this.MaxValue, out maximumSize);

            // Valid datastore check.
            if (this.SelectedSource == null || (this.SelectedSource != null && this.SelectedSource.DatastoreID.Equals(Guid.Empty)))
            {
                TridentMessageBox.ShowTridentErrorMessageBox(ManagementStudioResourceManager.GetString("GlobalSettingSelectValidDatastore"));
                result = false;
            }
            // Special character check.
            else if (checkSpecialChar.IsMatch(this.MinValue) || checkSpecialChar.IsMatch(this.MaxValue))
            {
                TridentMessageBox.ShowTridentErrorMessageBox(ManagementStudioResourceManager.GetString("GlobalSettingSpclCharException"));
                result = false;
            }
            // If given size is greater than the size of Int32.
            else if (!isMaxSizeValid || !isMinSizeValid)
            {
                TridentMessageBox.ShowTridentErrorMessageBox(ManagementStudioResourceManager.GetString("GlobalSettingOutOfRangeException", Int32.MaxValue.ToString()));
                result = false;
            }
            // If minimum size is less than 0.
            else if (Int32.Parse(this.MinValue) <= 0)
            {
                TridentMessageBox.ShowTridentErrorMessageBox(ManagementStudioResourceManager.GetString("GlobalSettingMinSizeException"));
                result = false;
            }
            // if maximum size is less than minimum size.
            else if (Int32.Parse(this.MaxValue) <= Int32.Parse(this.MinValue))
            {
                TridentMessageBox.ShowTridentErrorMessageBox(ManagementStudioResourceManager.GetString("GlobalSettingMaxSizeException"));
                result = false;
            }

            return result;
        }

        #endregion

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Fires the property changed event.
        /// </summary>
        /// <param name="propertyName">Name of the property which has been modified.</param>
        private void OnNotifyPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion
    }
}
